using Avalonia.Collections;
using Avalonia.Controls;
using FileManager;
using LibationFileManager;
using ReactiveUI;
using System.Collections.Generic;
using System.Linq;

#nullable enable
namespace LibationAvalonia.Dialogs
{
	public partial class EditReplacementChars : DialogWindow
	{
		private Configuration? Config { get; }

		public bool EnvironmentIsWindows => Configuration.IsWindows;

		private readonly AvaloniaList<ReplacementsExt> SOURCE = new();
		public DataGridCollectionView Replacements { get; }
		public EditReplacementChars()
		{
			InitializeComponent();

			Replacements = new(SOURCE);

			if (Design.IsDesignMode)
			{
				LoadTable(ReplacementCharacters.Default(true).Replacements);
			}

			DataContext = this;
		}

		public EditReplacementChars(Configuration config) : this()
		{
			Config = config;
			LoadTable(config.ReplacementCharacters.Replacements);
		}

		public void Defaults(bool isNtfs)
			=> LoadTable(ReplacementCharacters.Default(isNtfs).Replacements);
		public void LoFiDefaults(bool isNtfs)
			=> LoadTable(ReplacementCharacters.LoFiDefault(isNtfs).Replacements);
		public void Barebones(bool isNtfs)
			=> LoadTable(ReplacementCharacters.Barebones(isNtfs).Replacements);

		public new void Close() => base.Close();
		public new void SaveAndClose()
		{
			if (Config is not null)
			{
				var replacements = SOURCE.Where(r => !r.IsDefault).Select(r => r.ToReplacement()).ToArray();
				Config.ReplacementCharacters = new ReplacementCharacters { Replacements = replacements };
			}
			base.SaveAndClose();
		}

		private void LoadTable(IReadOnlyList<Replacement> replacements)
		{
			SOURCE.Clear();
			SOURCE.AddRange(replacements.Select(r => new ReplacementsExt(r)));
			SOURCE.Add(new ReplacementsExt());
		}

		private bool ColumnIsCharacter(DataGridColumn column)
			=> column.DisplayIndex is 0;

		private bool ColumnIsReplacement(DataGridColumn column)
			=> column.DisplayIndex is 1;

		private bool RowIsReadOnly(DataGridRow row)
			=> row.DataContext is ReplacementsExt rep && rep.Mandatory;

		private bool CanDeleteSelectedItem(ReplacementsExt selectedItem)
			=> !selectedItem.Mandatory && (!selectedItem.IsDefault || SOURCE[^1] != selectedItem);

		private void replacementGrid_BeginningEdit(object sender, DataGridBeginningEditEventArgs e)
		{
			e.Cancel = RowIsReadOnly(e.Row) && !ColumnIsReplacement(e.Column);
		}

		private void replacementGrid_CellEditEnding(object? sender, DataGridCellEditEndingEventArgs e)
		{
			//Disallow duplicates of CharacterToReplace
			if (ColumnIsCharacter(e.Column) && e.Row.DataContext is ReplacementsExt r && r.CharacterToReplace.Length > 0 && SOURCE.Count(rep => rep.CharacterToReplace == r.CharacterToReplace) > 1)
			{
				r.CharacterToReplace = "";
				e.Cancel = true;
			}
		}

		private void replacementGrid_CellEditEnded(object? sender, DataGridCellEditEndedEventArgs e)
		{
			if (ColumnIsCharacter(e.Column) && e.Row.DataContext is ReplacementsExt r && r.CharacterToReplace.Length > 0 && !SOURCE[^1].IsDefault)
			{
				Replacements.AddNew();
			}
		}

		private void replacementGrid_KeyDown(object? sender, Avalonia.Input.KeyEventArgs e)
		{
			if (e.Key == Avalonia.Input.Key.Delete && (sender as DataGrid)?.SelectedItem is ReplacementsExt r && CanDeleteSelectedItem(r))
			{
				if (Replacements.IsEditingItem)
				{
					if (Replacements.CanCancelEdit)
						Replacements.CancelEdit();
					else
						Replacements.CommitEdit();
				}
				if (Replacements.IsAddingNew)
				{
					Replacements.CancelNew();
				}
				if (Replacements.CanRemove)
				{
					Replacements.Remove(r);
				}
			}
		}

		public class ReplacementsExt : ViewModels.ViewModelBase
		{
			public ReplacementsExt()
			{
				ReplacementText = string.Empty;
				Description = string.Empty;
				CharacterToReplace = string.Empty;
			}
			public ReplacementsExt(Replacement replacement)
			{
				CharacterToReplace = replacement.CharacterToReplace == default ? "" : replacement.CharacterToReplace.ToString();
				ReplacementText = replacement.ReplacementString;
				Description = replacement.Description;
				Mandatory = replacement.Mandatory;
			}

			public string ReplacementText { get => field; set => this.RaiseAndSetIfChanged(ref field, value); }
			public string Description { get => field; set => this.RaiseAndSetIfChanged(ref field, value); }
			public string CharacterToReplace { get => field; set => this.RaiseAndSetIfChanged(ref field, value); }
			public char Character => string.IsNullOrEmpty(CharacterToReplace) ? default : CharacterToReplace[0];
			public bool IsDefault => !Mandatory && string.IsNullOrEmpty(CharacterToReplace);
			public bool Mandatory { get; }

			public Replacement ToReplacement()
				=> new(Character, ReplacementText, Description) { Mandatory = Mandatory };
		}
	}
}
